home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / os2 / lxlt113.zip / SOURCES / RTL / CRT.PAS < prev   
Pascal/Delphi Source File  |  1996-04-16  |  17KB  |  655 lines

  1. {█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█}
  2. {█                                                       █}
  3. {█      Virtual Pascal Runtime Library.  Version 1.0.    █}
  4. {█      CRT Interface unit for OS/2                      █}
  5. {█      ─────────────────────────────────────────────────█}
  6. {█      Copyright (C) 1995 B&M&T Corporation             █}
  7. {█      ─────────────────────────────────────────────────█}
  8. {█      Written by Vitaly Miryanov                       █}
  9. {█                                                       █}
  10. {▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
  11.  
  12. {$S-,R-,Q-,I-,Cdecl-,OrgName-,AlignRec- ,Delphi-}
  13.  
  14. unit Crt;
  15.  
  16. interface
  17.  
  18. uses Use32;
  19.  
  20. const
  21.  
  22. { CRT modes }
  23.  
  24.   BW40          = 0;            { 40x25 B/W on Color Adapter   }
  25.   CO40          = 1;            { 40x25 Color on Color Adapter }
  26.   BW80          = 2;            { 80x25 B/W on Color Adapter   }
  27.   CO80          = 3;            { 80x25 Color on Color Adapter }
  28.   Mono          = 7;            { 80x25 on Monochrome Adapter  }
  29.   Font8x8       = 256;          { Add-in for 8x8 font          }
  30.  
  31. { Foreground and background color constants }
  32.  
  33.   Black         = 0;
  34.   Blue          = 1;
  35.   Green         = 2;
  36.   Cyan          = 3;
  37.   Red           = 4;
  38.   Magenta       = 5;
  39.   Brown         = 6;
  40.   LightGray     = 7;
  41.  
  42. { Foreground color constants }
  43.  
  44.   DarkGray      = 8;
  45.   LightBlue     = 9;
  46.   LightGreen    = 10;
  47.   LightCyan     = 11;
  48.   LightRed      = 12;
  49.   LightMagenta  = 13;
  50.   Yellow        = 14;
  51.   White         = 15;
  52.  
  53. { Add-in for blinking }
  54.  
  55.   Blink         = 128;
  56.  
  57. { Interface variables }
  58.  
  59. const
  60.   CheckBreak: Boolean = True;   { Enable Ctrl-Break      }
  61.   CheckEOF: Boolean = False;    { Allow Ctrl-Z for EOF?  }
  62.   TextAttr: Byte = LightGray;   { Current text attribute }
  63.   RedirOutput: boolean = False; {True if stdOut is redirected}
  64.   RedirInput: boolean = False;  {True if stdIn is redirected}
  65.  
  66. var
  67.   LastMode: Word;               { Current text mode }
  68.   WindMin: Word;                { Window upper left coordinates }
  69.   WindMax: Word;                { Window lower right coordinates }
  70.  
  71. { The following interface variables are not used (for compatibility only) }
  72.  
  73. const
  74.   DirectVideo: Boolean = False; { Enable direct video addressing }
  75.   CheckSnow: Boolean = True;    { Enable snow filtering }
  76.  
  77. { Interface procedures }
  78.  
  79. procedure AssignCrt(var F: Text);
  80. function KeyPressed: Boolean;
  81. function ReadKey: Char;
  82. procedure TextMode(Mode: Integer);
  83. procedure Window(X1,Y1,X2,Y2: Byte);
  84. procedure GotoXY(X,Y: Byte);
  85. function WhereX: Byte;
  86. function WhereY: Byte;
  87. procedure ClrScr;
  88. procedure ClrEol;
  89. procedure InsLine;
  90. procedure DelLine;
  91. procedure TextColor(Color: Byte);
  92. procedure TextBackground(Color: Byte);
  93. procedure LowVideo;
  94. procedure HighVideo;
  95. procedure NormVideo;
  96. procedure Delay(MS: Longint);
  97.  
  98. { The following procedures are not implemented
  99.  
  100. procedure Sound(Hz: Word);
  101. procedure NoSound;
  102.  
  103. use new procedure PlaySound instead
  104.  
  105. }
  106.  
  107. procedure PlaySound(Freq,Duration: Longint);
  108.  
  109. implementation
  110.  
  111. uses Dos, Os2Def, Os2Base, Xcpt;
  112.  
  113. { Private variables }
  114.  
  115. var
  116.   VioMode: VioModeInfo;
  117.   NormAttr: Byte;
  118.   DelayCount: Longint;
  119.  
  120. const
  121.   ScanCode: Byte = 0;
  122.  
  123. { Determines if a key has been pressed on the keyboard and returns True }
  124. { if a key has been pressed                                             }
  125.  
  126. function KeyPressed: Boolean;
  127. var
  128.   Key: KbdKeyInfo;
  129. begin
  130.   KbdPeek(Key,0);
  131.   KeyPressed := (ScanCode <> 0) or ((Key.fbStatus and kbdtrf_Final_Char_In) <> 0);
  132. end;
  133.  
  134. { Reads a character from the keyboard and returns a character or an     }
  135. { extended scan code.                                                   }
  136.  
  137. function ReadKey: Char;
  138. var
  139.   Key: KbdKeyInfo;
  140. begin
  141.  if RedirInput
  142.   then Read(Input, Key.chChar)
  143.   else begin
  144.         If ScanCode <> 0
  145.          then begin
  146.                ReadKey  := Chr(ScanCode);
  147.                ScanCode := 0;
  148.               end
  149.          else begin
  150.                KbdCharIn(Key,io_Wait,0);
  151.                case Key.chChar of
  152.                 #0:
  153.                  ScanCode := Key.chScan;
  154.                 #$E0:           {   Up, Dn, Left Rt Ins Del Home End PgUp PgDn C-Home C-End C-PgUp C-PgDn C-Left C-Right C-Up C-Dn }
  155.                  if Key.chScan in [$48,$50,$4B,$4D,$52,$53,$47, $4F,$49, $51, $77,   $75,  $84,   $76,   $73,   $74,    $8D, $91]
  156.                   then begin
  157.                         ScanCode := Key.chScan;
  158.                         Key.chChar := #0;
  159.                        end;
  160.                end;
  161.               end;
  162.        end;
  163.  ReadKey := Key.chChar;
  164. end;
  165.  
  166. { Reads normal character attribute }
  167.  
  168. procedure ReadNormAttr;
  169. var
  170.   Cell,Size: SmallWord;
  171. begin
  172.   Size := 2;
  173.   VioReadCellStr(Cell, Size, WhereY-1, WhereX-1, 0);
  174.   NormAttr := Hi(Cell) and $7F;
  175.   NormVideo;
  176. end;
  177.  
  178. { Setups window coordinates }
  179.  
  180. procedure SetWindowPos;
  181. begin
  182.   WindMin := 0;
  183.   WindMax := VioMode.Col - 1 + (VioMode.Row - 1) shl 8;
  184. end;
  185.  
  186. { Stores current video mode in LastMode }
  187.  
  188. procedure GetLastMode;
  189. begin
  190.   VioMode.cb := SizeOf(VioMode);
  191.   VioGetMode(VioMode, 0);
  192.   with VioMode do
  193.   begin
  194.     if Col = 40 then LastMode := BW40 else LastMode := BW80;
  195.     if (fbType and vgmt_DisableBurst) = 0 then
  196.       if LastMode = BW40 then LastMode := CO40 else LastMode := CO80;
  197.     if Color = 0 then LastMode := Mono;
  198.     if Row > 25 then Inc(LastMode,Font8x8);
  199.   end;
  200. end;
  201.  
  202. { Selects a specific text mode. The valid text modes are:               }
  203. {   BW40: 40x25 Black and white                                         }
  204. {   CO40  40x25 Color                                                   }
  205. {   BW80  80x25 Black and white                                         }
  206. {   CO80  80x25 Color                                                   }
  207. {   Mono  80x25 Black and white                                         }
  208. {   Font8x8 (Add-in) 43-/50-line mode                                   }
  209.  
  210. procedure TextMode(Mode: Integer);
  211. var BiosMode: Byte; Cell: SmallWord; VideoConfig: VioConfigInfo;
  212. begin
  213.   GetLastMode;
  214.   TextAttr := LightGray;
  215.   BiosMode := Lo(Mode);
  216.   VideoConfig.cb := SizeOf(VideoConfig);
  217.   VioGetConfig(0, VideoConfig, 0);
  218.   with VioMode do
  219.   begin
  220.     cb := SizeOf(VioMode);
  221.     fbType := vgmt_Other;
  222.     Color := colors_16;         { Color }
  223.     Row := 25;                  { 80x25 }
  224.     Col := 80;
  225.     VRes := 400;
  226.     HRes := 720;
  227.     case BiosMode of            { 40x25 }
  228.       BW40,CO40:
  229.         begin
  230.           Col := 40; HRes := 360;
  231.         end;
  232.     end;
  233.     if (Mode and Font8x8) <> 0 then
  234.     case VideoConfig.Adapter of { 80x43 }
  235.       display_Monochrome..display_CGA: ;
  236.       display_EGA:
  237.         begin
  238.           Row := 43; VRes := 350; HRes := 640;
  239.         end;
  240.       else                      { 80x50 }
  241.         begin
  242.           Row := 50; VRes := 400; HRes := 720;
  243.         end;
  244.     end;
  245.     case BiosMode of            { Black and white }
  246.       BW40,BW80: fbType := vgmt_Other + vgmt_DisableBurst;
  247.       Mono:
  248.         begin                   { Monochrome }
  249.           HRes := 720; VRes := 350; Color := 0; fbType := 0;
  250.         end;
  251.     end;
  252.   end;
  253.   VioSetMode(VioMode, 0);
  254.   VioGetMode(VioMode, 0);
  255.   NormVideo;
  256.   SetWindowPos;
  257.   Cell := Ord(' ') + TextAttr shl 8;    { Clear entire screen }
  258.   VioScrollUp(0,0,65535,65535,65535,Cell,0);
  259. end;
  260.  
  261. { Defines a text window on the screen.                                  }
  262.  
  263. procedure Window(X1,Y1,X2,Y2: Byte);
  264. begin
  265.   if (X1 <= X2) and (Y1 <= Y2) then
  266.   begin
  267.     Dec(X1);
  268.     Dec(Y1);
  269.     if (X1 >= 0) and (Y1 >= 0) then
  270.     begin
  271.       Dec(X2);
  272.       Dec(Y2);
  273.       if (X2 < VioMode.Col) and (Y2 < VioMode.Row) then
  274.       begin
  275.         WindMin := X1 + Y1 shl 8;
  276.         WindMax := X2 + Y2 shl 8;
  277.         GotoXY(1,1);
  278.       end;
  279.     end;
  280.   end;
  281. end;
  282.  
  283. { Moves the cursor to the given coordinates within the screen.          }
  284.  
  285. procedure GotoXY(X,Y: Byte);
  286. var
  287.   X1,Y1: Word;
  288. begin
  289.   if (X > 0) and (Y > 0) then
  290.   begin
  291.     X1 := X - 1 + Lo(WindMin);
  292.     Y1 := Y - 1 + Hi(WindMin);
  293.     if (X1 <= Lo(WindMax)) and (Y1 <= Hi(WindMax)) then VioSetCurPos(Y1,X1,0);
  294.   end;
  295. end;
  296.  
  297. { Returns the X coordinate of the current cursor location.              }
  298.  
  299. function WhereX: Byte;
  300. var
  301.   X,Y: SmallWord;
  302. begin
  303.   VioGetCurPos(Y,X,0);
  304.   WhereX := X - Lo(WindMin) + 1;
  305. end;
  306.  
  307. { Returns the Y coordinate of the current cursor location.              }
  308.  
  309. function WhereY: Byte;
  310. var
  311.   X,Y: SmallWord;
  312. begin
  313.   VioGetCurPos(Y,X,0);
  314.   WhereY := Y - Hi(WindMin) + 1;
  315. end;
  316.  
  317. { Clears the screen and returns the cursor to the upper-left corner.    }
  318.  
  319. procedure ClrScr;
  320. var
  321.   Cell: SmallWord;
  322. begin
  323.   Cell := Ord(' ') + TextAttr shl 8;
  324.   VioScrollUp(Hi(WindMin),Lo(WindMin),Hi(WindMax),Lo(WindMax),Hi(WindMax)-Hi(WindMin)+1,Cell,0);
  325.   GotoXY(1,1);
  326. end;
  327.  
  328. { Clears all characters from the cursor position to the end of the line }
  329. { without moving the cursor.                                            }
  330.  
  331. procedure ClrEol;
  332. var
  333.   Cell,X,Y: SmallWord;
  334. begin
  335.   Cell := Ord(' ') + TextAttr shl 8;
  336.   VioGetCurPos(Y,X,0);
  337.   VioScrollUp(Y,X,Y,Lo(WindMax),1,Cell,0);
  338. end;
  339.  
  340. { Inserts an empty line at the cursor position.                         }
  341.  
  342. procedure InsLine;
  343. var
  344.   Cell,X,Y: SmallWord;
  345. begin
  346.   Cell := Ord(' ') + TextAttr shl 8;
  347.   VioGetCurPos(Y,X,0);
  348.   VioScrollDn(Y,Lo(WindMin),Hi(WindMax),Lo(WindMax),1,Cell,0);
  349. end;
  350.  
  351. { Deletes the line containing the cursor.                               }
  352.  
  353. procedure DelLine;
  354. var
  355.   Cell,X,Y: SmallWord;
  356. begin
  357.   Cell := Ord(' ') + TextAttr shl 8;
  358.   VioGetCurPos(Y,X,0);
  359.   VioScrollUp(Y,Lo(WindMin),Hi(WindMax),Lo(WindMax),1,Cell,0);
  360. end;
  361.  
  362. { Selects the foreground character color.                               }
  363.  
  364. procedure TextColor(Color: Byte);
  365. begin
  366.   if Color > White then Color := (Color and $0F) or $80;
  367.   TextAttr := (TextAttr and $70) or Color;
  368. end;
  369.  
  370. { Selects the background color.                                         }
  371.  
  372. procedure TextBackground(Color: Byte);
  373. begin
  374.   TextAttr := (TextAttr and $8F) or ((Color and $07) shl 4);
  375. end;
  376.  
  377. { Selects low intensity characters.                                     }
  378.  
  379. procedure LowVideo;
  380. begin
  381.   TextAttr := TextAttr and $F7;
  382. end;
  383.  
  384. { Selects normal intensity characters.                                  }
  385.  
  386. procedure NormVideo;
  387. begin
  388.   TextAttr := NormAttr;
  389. end;
  390.  
  391. { Selects high-intensity characters.                                    }
  392.  
  393. procedure HighVideo;
  394. begin
  395.   TextAttr := TextAttr or $08;
  396. end;
  397.  
  398. { Waits for next timer tick or delays 1ms }
  399.  
  400. function DelayLoop(Count: Longint; var StartValue: ULong): Longint;
  401. var
  402.   Value: ULong;
  403. begin
  404.   repeat
  405.     DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,Value,SizeOf(Value));
  406.     Dec(Count);
  407.   until (Value <> StartValue) or (Count = -1);
  408.   StartValue := Value;
  409.   DelayLoop := Count;
  410. end;
  411.  
  412. { Delays a specified number of milliseconds. DosSleep is too inexact on }
  413. { small time intervals. More over, the least time interval for DosSleep }
  414. { is 1 timer tick (usually 31ms). That is why for small time intervals  }
  415. { special delay routine is used. Unfortunately, even this routine cannot}
  416. { be exact in the multitasking environment.                             }
  417.  
  418. procedure Delay(MS: Longint);
  419. var
  420.   StartValue,Value: ULong;
  421.   Count: Longint;
  422. begin
  423.   if MS >= 5*31 then DosSleep(MS)
  424.  else
  425.   begin
  426.     DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,StartValue,SizeOf(StartValue));
  427.     Value := StartValue;
  428.     Count := MS;
  429.     repeat
  430.       DelayLoop(DelayCount,Value);
  431.       Dec(Count)
  432.     until (Value-StartValue >= MS) or (Count <= 0);
  433.   end;
  434. end;
  435.  
  436. { Calculates 1ms delay count for DelayLoop routine. }
  437. { CalcDelayCount is called once at startup.         }
  438.  
  439. procedure CalcDelayCount;
  440. var
  441.   Interval,StartValue,Value: ULong;
  442. begin
  443.   DosQuerySysInfo(qsv_Timer_Interval,qsv_Timer_Interval,Interval,SizeOf(Interval));
  444.   DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,StartValue,SizeOf(StartValue));
  445.   repeat
  446.     DosQuerySysInfo(qsv_Ms_Count,qsv_Ms_Count,Value,SizeOf(Value));
  447.   until Value <> StartValue;
  448.   DelayCount := -DelayLoop(-1,Value) div Interval * 10;
  449. end;
  450.  
  451. { Plays sound of a specified frequency and duration.                    }
  452.  
  453. procedure PlaySound(Freq,Duration: Longint);
  454. begin
  455.   DosBeep(Freq,Duration);
  456. end;
  457.  
  458. { Do line feed operation }
  459.  
  460. procedure LineFeed;
  461. var
  462.   Cell: SmallWord;
  463. begin
  464.   Cell := Ord(' ') + TextAttr shl 8;
  465.   VioScrollUp(Hi(WindMin),Lo(WindMin),Hi(WindMax),Lo(WindMax),1,Cell,0);
  466. end;
  467.  
  468. { Outputs packed string to the CRT device }
  469.  
  470. procedure WritePackedString(S: PChar; Len: Longint);
  471. var X,Y,cX,cY : SmallWord;
  472.     i,sP,sL   : Longint;
  473.     C         : Char;
  474. begin
  475.  VioGetCurPos(Y,X,0);
  476.  i := 0;
  477.  While i < Len do
  478.   begin
  479.    sP := i; sL := 0;
  480.    cX := X; cY := Y;
  481.    repeat
  482.     C := S[i]; Inc(i);
  483.     if C in [^J,^M,^H,^G] then break;
  484.     Inc(sL); Inc(X);
  485.    until (i >= pred(Len)) or (X > Lo(WindMax));
  486.    if sL <> 0 then VioWrtCharStrAtt(@S[sP], sL, cY, cX, TextAttr, 0);
  487.    case C of
  488.     ^J : if Y >= Hi(WindMax) then LineFeed else Inc(Y); { Line Feed       }
  489.     ^M : X := Lo(WindMin);                              { Carriage return }
  490.     ^H : if X > Lo(WindMin) then Dec(X);                { Backspace       }
  491.     ^G : begin                                          { Bell            }
  492.           if (X <> cX) or (Y <> cY) then VioSetCurPos(Y,X,0);
  493.           cX := X; cY := Y;
  494.           VioWrtTTY(@C,1,0);
  495.          end;
  496.    end;
  497.    if X > Lo(WindMax)
  498.     then begin
  499.           X := Lo(WindMin);
  500.           Inc(Y);
  501.          end;
  502.    if Y > Hi(WindMax)
  503.     then begin
  504.           LineFeed;
  505.           Y := Hi(WindMax);
  506.          end;
  507.    if (X <> cX) or (Y <> cY) then VioSetCurPos(Y,X,0);
  508.   end;
  509. end;
  510.  
  511. { CRT text file I/O functions }
  512.  
  513. function CrtRead(var F: Text): Longint;
  514. var
  515.   CurPos : Longint;
  516.   C      : Char;
  517.   TR     : TextRec absolute F;
  518. begin
  519.   with TR do
  520.   begin
  521.     CurPos := 0;
  522.     repeat
  523.       ScanCode := 0;
  524.       C := ReadKey;
  525.       case C of
  526.         ^H:                     { Backspace }
  527.           if CurPos > 0 then
  528.           begin
  529.             WritePackedString(^H' '^H, 3);
  530.             Dec(CurPos);
  531.           end;
  532.         #27:                    { Escape }
  533.           while CurPos > 0 do
  534.           begin
  535.             WritePackedString(^H' '^H, 3);
  536.             Dec(CurPos);
  537.           end;
  538.         ' '..#255:
  539.           if CurPos < BufSize - 2 then
  540.           begin
  541.             BufPtr^[CurPos] := C;
  542.             Inc(CurPos);
  543.             WritePackedString(@C,1);
  544.           end;
  545.       end; { case }
  546.     until (C = ^M) or (CheckEOF and (C = ^Z));
  547.     BufPtr^[CurPos] := C;
  548.     Inc(CurPos);
  549.     if C = ^M then              { Carriage Return }
  550.     begin
  551.       BufPtr^[CurPos] := ^J;    { Line Feed }
  552.       Inc(CurPos);
  553.       WritePackedString(^M^J,2);
  554.     end;
  555.     BufPos := 0;
  556.     BufEnd := CurPos;
  557.   end;
  558.   CrtRead := 0;                 { I/O result = 0: success }
  559. end;
  560.  
  561. function CrtWrite(var F: Text): Longint;
  562. var TR : TextRec absolute F;
  563. begin
  564.   with TR do
  565.   begin
  566.     WritePackedString(PChar(BufPtr),BufPos);
  567.     BufPos := 0;
  568.   end;
  569.   CrtWrite := 0;                { I/O result = 0: success }
  570. end;
  571.  
  572. function CrtReturn(var F: Text): Longint;
  573. begin
  574.   CrtReturn := 0;               { I/O result = 0: success }
  575. end;
  576.  
  577. function CrtOpen(var F: Text): Longint;
  578. var TR : TextRec absolute F;
  579. begin
  580.   with TR do
  581.   begin
  582.     CloseFunc := @CrtReturn;
  583.     if Mode = fmInput then
  584.     begin
  585.       InOutFunc := @CrtRead;
  586.       FlushFunc := @CrtReturn;
  587.     end
  588.    else
  589.     begin
  590.       Mode := fmOutput;
  591.       InOutFunc := @CrtWrite;
  592.       FlushFunc := @CrtWrite;
  593.     end;
  594.   end;
  595.   CrtOpen := 0;                 { I/O result = 0: success }
  596. end;
  597.  
  598. { Associates a text file with CRT device.                               }
  599.  
  600. procedure AssignCrt(var F: Text);
  601. var TR : TextRec absolute F;
  602. begin
  603.   with TR do
  604.   begin
  605.     Handle := $FFFFFFFF;
  606.     Mode := fmClosed;
  607.     BufSize := SizeOf(Buffer);
  608.     BufPtr := @Buffer;
  609.     OpenFunc := @CrtOpen;
  610.     Name[0] := #0;
  611.   end;
  612. end;
  613.  
  614. { Signal Handler }
  615.  
  616. function CtrlBreakHandler(Report:       PExceptionReportRecord;
  617.                           Registration: PExceptionRegistrationRecord;
  618.                           Context:      PContextRecord;
  619.                           P:            Pointer): ULong; cdecl;
  620. begin
  621.   if not CheckBreak and (Report^.ExceptionNum = xcpt_Signal)
  622.     then CtrlBreakHandler := xcpt_Continue_Execution
  623.     else CtrlBreakHandler := xcpt_Continue_Search;
  624. end;
  625.  
  626. Procedure AssignConToCrt;
  627. var hType,hAttr : Longint;
  628. begin
  629.  DosQueryHType(0, hType, hAttr);
  630.  if hType and 3 = 1
  631.   then begin
  632.         AssignCrt(Input);
  633.         Reset(Input);
  634.        end
  635.   else RedirInput := True;
  636.  DosQueryHType(1, hType, hAttr);
  637.  if hType and 3 = 1
  638.   then begin
  639.         AssignCrt(Output);
  640.         ReWrite(Output);
  641.        end
  642.   else RedirOutput := True;
  643. end;
  644.  
  645. begin
  646.  GetLastMode;
  647.  if (VioMode.fbType and vgmt_Graphics) <> 0 then TextMode(CO80);
  648.  ReadNormAttr;
  649.  SetWindowPos;
  650.  AssignConToCrt;
  651.  CalcDelayCount;
  652.  SetExceptionHandler(@CtrlBreakHandler);
  653. end.
  654.  
  655.